#include "ShaderHandler.h"

#define	MAX_STRING_LENGTH			256

ShaderHandler::ShaderHandler(void)
{
	m_program = NULL;
	m_context = NULL;
	m_parameters.clear();
}

ShaderHandler::~ShaderHandler(void)
{
}

void ShaderHandler::SetShaderType(CGGLenum shader_type)
{
	m_type = shader_type;	
}

void ShaderHandler::AddParameter(char *binding_name, CGGL_PARAMETER_TYPE2 type, void *ptr)//when reload the shader
{//puts("c_shader::AddParameter()");
	if(m_program == NULL) return;
	c_shader_parameter new_parameter;

	if(ptr != NULL)
		new_parameter.m_ptrs = ptr;

	new_parameter.type = type;
	new_parameter.m_binding_name.append(binding_name);
	new_parameter.m_cgp = cgGetNamedParameter(m_program, new_parameter.m_binding_name.c_str());

	m_parameters.push_back(new_parameter);
}




void ShaderHandler::RefreshParameter()//every time when render each frame
{	//puts("c_shader::RefreshParameter()");
	int	tex_id = 1;
	int* id;
	float* value;
	for(int i=0; i<m_parameters.size(); i++)
	{
		switch(m_parameters[i].type)
		{
		case CG_GL_VECTOR_1D:
			cgGLSetParameter1fv(m_parameters[i].m_cgp, (float *)m_parameters[i].m_ptrs);
				value = (float*)m_parameters[i].m_ptrs;
			break;
		case CG_GL_VECTOR_2D:
			cgGLSetParameter2fv(m_parameters[i].m_cgp, (float *)m_parameters[i].m_ptrs);
			break;
		case CG_GL_VECTOR_3D:
			cgGLSetParameter3fv(m_parameters[i].m_cgp, (float *)m_parameters[i].m_ptrs);
			break;
		case CG_GL_VECTOR_4D:
			cgGLSetParameter4fv(m_parameters[i].m_cgp, (float *)m_parameters[i].m_ptrs);
				value = (float*)m_parameters[i].m_ptrs;
			break;
		case CG_GL_MODELVIEW_MTX:
			cgGLSetStateMatrixParameter(m_parameters[i].m_cgp, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);
		
		//GLfloat buf[16];
		//glGetFloatv(GL_MODELVIEW_MATRIX, buf);
		//printMatrix2( buf );
			
			break;
		case CG_GL_MODELVIEW_PROJECTION_MTX:
			cgGLSetStateMatrixParameter(m_parameters[i].m_cgp, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
			break;
		case CG_GL_MODELVIEW_IT_MTX:
			cgGLSetStateMatrixParameter(m_parameters[i].m_cgp, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE);
			break;
		case CG_GL_ARBITRARY_MTX:
			cgGLSetMatrixParameterfc(m_parameters[i].m_cgp, (float *)m_parameters[i].m_ptrs);
			
			value = (float *)m_parameters[i].m_ptrs;
			
			break;
		case CG_GL_TEXTURE_2D:
		case CG_GL_TEXTURE_CUBE_MAP:
		case CG_GL_TEXTURE_RECT:
			id = (int*)m_parameters[i].m_ptrs; //the id of textures in the pool
			cgGLSetTextureParameter(m_parameters[i].m_cgp, *id);
			cgGLEnableTextureParameter(m_parameters[i].m_cgp);
			//printf("%s %d\n", m_parameters[i].m_binding_name.c_str(), *id);
			break;
		}
	}

}

bool ShaderHandler::Load(const char *filename, CGGLenum type)//when load material, when reload the shader
{	
	//puts("c_shader::Load()");
	if(m_program){
		//cgDestroyProgram(m_program);
		//puts("destroy"); getchar();
	}
	m_parameters.clear();

	m_filename.clear();
	m_filename.append(filename);
	m_type = type;
	m_profile = cgGLGetLatestProfile(m_type);
	//printf("vertex profile: %s\n", cgGetProfileString(m_profile)); getchar();
	//m_profile = CGprofile(
	if(m_type == CG_GL_VERTEX){
		//printf("%d\n", m_context);
		//m_profile = CG_PROFILE_GLSLV;
		//m_profile = CG_PROFILE_GP4VP;
		m_program = cgCreateProgramFromFile(m_context, CG_SOURCE, m_filename.c_str(), m_profile, NULL, NULL);
	}else if(m_type == CG_GL_FRAGMENT){
		//m_profile = CG_PROFILE_GLSLF;
		//m_profile = CG_PROFILE_GP4FP;
		//printf("%d\n", m_context);
		m_program = cgCreateProgramFromFile(m_context, CG_SOURCE, m_filename.c_str(), m_profile, NULL, NULL);
	}else{
		puts("fuck"); getchar();
	}
	//fprintf(stderr, "LAST LISTING----%s----\n", cgGetLastListing(m_context));
	//fprintf(stderr, "---- PROGRAM BEGIN ----\n%s---- PROGRAM END ----\n\n\n\n",
	cgGetProgramString(m_program, CG_COMPILED_PROGRAM);

	//getchar();


	if(m_program != NULL)
	{
		cgGLLoadProgram(m_program);
		if(m_program == NULL)
			return false;
		return true;
	}
	else
		return false;

	
}
void ShaderHandler::bind()
{
	if(this->m_program)
	{
		cgGLBindProgram(this->m_program);
		cgGLEnableProfile(this->m_profile);
		this->RefreshParameter();
	}
	
}
void ShaderHandler::release()
{
	if(this->m_program)
		cgGLDisableProfile(this->m_profile);
	
}
void ShaderHandler::Unload()
{
	cgDestroyProgram(m_program);
}